/**
 * Copyright (c) 2017-present, Facebook, Inc. and its affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
#pragma once

#include <string>
#include <vector>

namespace facebook { namespace logdevice {

struct PrincipalIdentity {
  static constexpr const char* IDENTITY_USER = "USER";
  static constexpr const char* IDENTITY_SERVICE = "SERVICE_IDENTITY";
  static constexpr const char* IDENTITY_TIER = "TIER";
  static constexpr const char* IDENTITY_MACHINE = "MACHINE";
  static constexpr const char* IDENTITY_JOB = "JOB";

  /**
   * Principal type, one of Principal::well_known_principals
   */
  std::string type;

  /**
   * Vector of identities. Each identify is pair: type,name.
   * Example:
   * USER,testuser
   * MACHINE_TIER,dev
   */
  std::vector<std::pair<std::string, std::string>> identities;
  /*
   * Precomputed value generated by hashing together the strings of all the
   * identities.
   */
  uint64_t identities_hash{0};
  /**
   * Primary (first) identity. Used for logging only
   */
  std::pair<std::string, std::string> primary_identity;
  std::string client_address;
  std::string csid;

  PrincipalIdentity() = default;

  explicit PrincipalIdentity(const std::string& type);

  PrincipalIdentity(const std::string& type,
                    const std::pair<std::string, std::string>& identity);

  PrincipalIdentity(
      const std::string& type,
      const std::pair<std::string, std::string>& identity,
      const std::vector<std::pair<std::string, std::string>>& identities);

  void calculateIdentitiesHash();

  std::string toString() const;

  bool match(const std::string& idtype, const std::string& identity);
  static bool isValidIdentityType(const std::string& idType);

  /**
   * Checks whether this object repesents default empty identity.
   */
  bool isEmpty() {
    return type.empty();
  }

  bool operator==(const PrincipalIdentity& rhs) const {
    if (this == &rhs) {
      return true;
    }
    return type == rhs.type && primary_identity == rhs.primary_identity;
  }

  bool operator!=(const PrincipalIdentity& rhs) const {
    return !(*this == rhs);
  }
};

}} // namespace facebook::logdevice
